package handlers

import (
	"context"
	"sync"

	"github.com/liyaozong/mengo/common/db"
	"github.com/liyaozong/mengo/common/di"
	dbError "github.com/liyaozong/mengo/contracts/db"
	"github.com/liyaozong/mengo/contracts/logger"
	"github.com/liyaozong/mengo/contracts/models"
	"github.com/liyaozong/mengo/core/base/container"
	"github.com/liyaozong/mengo/core/base/interfaces"
	"gorm.io/driver/mysql"
	"gorm.io/driver/sqlite"
	"gorm.io/gorm"
)

type Database struct {
	ctx    context.Context
	config interfaces.Configuration
}

func NewDatabase(ctx context.Context, config interfaces.Configuration) Database {
	return Database{
		ctx:    ctx,
		config: config,
	}
}

func (d Database) newDBClient(lc logger.LoggingClient, driver string) (*gorm.DB, error) {
	config := &gorm.Config{
		DisableForeignKeyConstraintWhenMigrating: true,
	}

	switch driver {
	case "mysql":
		mysqlConfig := mysql.Config{
			DSN:                       d.config.GetDatabaseInfo().Dsn(), // DSN data source name
			DefaultStringSize:         128,                              // string 类型字段的默认长度
			SkipInitializeWithVersion: false,                            // 根据版本自动配置
		}
		if dc, err := gorm.Open(mysql.New(mysqlConfig), config); err == nil {
			return dc, nil
		} else {
			lc.Error("mysql connect fail", err)
			return nil, dbError.ErrUnsupportedDatabase
		}
	case "sqlite":
		if dc, err := gorm.Open(sqlite.Open(d.config.GetDatabaseInfo().Dsn()), config); err == nil {
			return dc, nil
		} else {
			lc.Error("sqlite connect fail", err)
			return nil, dbError.ErrUnsupportedDatabase
		}
	default:
		lc.Debug("not support db driver")
		return nil, dbError.ErrUnsupportedDatabase
	}
}

func (d Database) BootstrapHandler(ctx context.Context, wg *sync.WaitGroup, dic *di.Container) bool {
	lc := container.LoggingClientFrom(dic.Get)

	if dc, err := d.newDBClient(lc, d.config.GetDatabaseInfo().Driver); err == nil {
		dic.Update(di.ServiceConstructorMap{
			container.DBClientInterfaceName: func(get di.Get) interface{} {
				return dc
			},
		})

		dc.Use(&db.DbFieldPlugin{})

		//数据表初始化
		if err = dc.AutoMigrate(
			models.User{},
			models.Role{},
			models.Permission{},
		); err != nil {
			lc.Error("register table failed", err)
		}

		return true
	}
	return false
}
